home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene Storm
/
Scene Storm - Volume 1.iso
/
coding
/
c
/
unix
/
src
/
amigados.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-02
|
7KB
|
300 lines
#include "amiga.h"
#include "files.h"
#include "signals.h"
#include <exec/memory.h>
#include <fcntl.h>
#include <sys/termios.h>
#include <amiga/ioctl.h>
#include <string.h>
/* Code for fd's describing AmigaDOS files */
struct amigainfo
{
BPTR fh;
BPTR lock; /* A lock on the file (may be null) */
long protection; /* To be set when file is closed, -1 for none */
char interactive; /* True if file was interactive */
char deleted; /* True if file has been deleted but not closed */
};
static ULONG file_select_start(void *userinfo, int rd, int wr)
{
/* Input always immediately available, gniark */
return (ULONG)-1;
}
static void file_select_poll(void *userinfo, int *rd, int *wr)
{
/* Input always immediately available, gniark */
}
static int file_read(void *userinfo, void *buffer, unsigned int length)
{
struct amigainfo *info = userinfo;
BPTR fh = info->fh;
LONG cnt;
if (info->deleted) return 0;
if ((cnt = Read(fh, buffer, length)) == -1) ERROR;
return (int)cnt;
}
static int file_write(void *userinfo, void *buffer, unsigned int length)
{
struct amigainfo *info = userinfo;
BPTR fh = info->fh;
int cnt;
if (info->deleted) return 0;
if (info->interactive)
{
char *bufend = (char *)buffer + length;
/* Write by lines, more pleasant for user */
cnt = 0;
while (length)
{
char *end = buffer;
long nb;
unsigned len;
while (end < bufend && *end != '\n') end++;
if (end == bufend) len = end - (char *)buffer;
else len = end + 1 - (char *)buffer;
if ((nb = Write(fh, buffer, len)) == -1) ERROR;
cnt += nb;
if (nb != len) break;
buffer = end + 1;
length -= nb;
/* Interrupt write ? */
if (_handle_signals(_check_signals(0))) break;
}
}
else if ((cnt = Write(fh, buffer, length)) == -1) ERROR;
return cnt;
}
static int file_lseek(void *userinfo, long rpos, int mode)
{
struct amigainfo *info = userinfo;
BPTR fh = info->fh;
LONG pos, err;
if (info->deleted) return 0;
pos = Seek(fh, rpos, mode - 1);
err = IoErr();
if (pos == -1 || err)
{
errno = convert_oserr(err);
return -1;
}
pos = Seek(fh, 0, OFFSET_CURRENT);
if (pos == -1 || err)
{
errno = convert_oserr(err);
return -1;
}
return pos;
}
static int file_close(void *userinfo, int internal)
{
struct amigainfo *info = userinfo;
BPTR fh = info->fh;
long protection = info->protection;
char name[256];
int ok, deleted;
if (info->lock) UnLock(info->lock);
deleted = info->deleted;
free(info);
if (deleted) return 0;
ok = NameFromFH(fh, name, 256);
if (internal || Close(fh))
if (!ok || protection == -1 || SetProtection(name, protection)) return 0;
ERROR;
}
static int isfifo(BPTR fh)
/* Requires: IsInteractive(fh) */
/* Try & find out if fh is a fifo: file */
{
WaitForChar(fh, 0);
return IoErr() == ERROR_ACTION_NOT_KNOWN;
}
static int GetWinBounds (BPTR fh, long *width, long *height)
{
char buffer[16];
int ok = 0;
if (!isfifo(fh) && SetMode (fh, 1))
{
if ((Write (fh, "\x9b" "0 q", 4) == 4) &&
WaitForChar (fh, 10000L) &&
(Read (fh, buffer, sizeof (buffer)) > 9) &&
(buffer[0] == '\x9b'))
{
int y = StrToLong (buffer+5, height);
int x = StrToLong (buffer+5+y+1, width);
if ((x != -1) && (y != -1)) ok = 1;
}
SetMode (fh, 0);
}
return ok;
}
int _do_truncate(BPTR fh, off_t length)
{
int err, ret = -1;
long oldsize, oldpos;
oldpos = Seek(fh, 0, OFFSET_END);
oldsize = Seek(fh, 0, OFFSET_END);
if (!(err = IoErr()) &&
SetFileSize(fh, length, OFFSET_BEGINNING) == length)
{
if (oldsize < length)
{
/* Zero extra bytes */
off_t bufsize = length - oldsize, left = bufsize;
char *buf;
char reserve[512];
if (!(buf = AllocMem(bufsize, MEMF_CLEAR)))
{
bufsize = AvailMem(MEMF_LARGEST) / 2;
if (bufsize < 512 || !(buf = AllocMem(bufsize, MEMF_CLEAR)))
{
bufsize = 512;
buf = reserve;
memset(reserve, 0, 512);
}
}
while (left > 0)
{
long count = left > bufsize ? bufsize : left;
chkabort();
if (Write(fh, buf, count) != count)
{
err = IoErr();
break;
}
left -= count;
}
if (buf != reserve) FreeMem(buf, bufsize);
}
if (!err) ret = 0;
}
if (oldpos < length) Seek(fh, oldpos, OFFSET_BEGINNING);
if (ret) errno = convert_oserr(err);
return ret;
}
static int file_ioctl(void *userinfo, int request, void *data)
{
struct amigainfo *info = userinfo;
BPTR fh = info->fh;
if (!info->deleted)
switch (request)
{
case TIOCGWINSZ: {
struct winsize *ws = data;
long col, row;
if (info->interactive && GetWinBounds(fh, &col, &row))
{
ws->ws_col = col; ws->ws_row = row;
return 0;
}
errno = ENOTTY;
return -1;
}
case _AMIGA_INTERACTIVE: {
int *inter = data;
*inter = IsInteractive(fh);
return 0;
}
case _AMIGA_GET_FH: {
BPTR *gotfh = data;
*gotfh = fh;
return 0;
}
case _AMIGA_FREE_FH: return 0;
case _AMIGA_TRUNCATE: {
off_t length = *(off_t *)data;
return _do_truncate(fh, length);
}
case _AMIGA_SETPROTECTION:
info->protection = *(long *)data;
return 0;
case _AMIGA_DELETE_IF_ME: {
BPTR nlock = *(BPTR *)data;
if (!info->lock) info->lock = DupLockFromFH(info->fh);
if (info->lock && SameLock(nlock, info->lock) == LOCK_SAME)
{
char name[256];
if (NameFromFH(fh, name, 256))
{
UnLock(nlock);
UnLock(info->lock);
Close(fh);
SetProtection(name, 0);
info->deleted = TRUE;
info->lock = info->fh = 0;
if (DeleteFile(name)) return 0;
}
}
ERROR;
}
}
errno = EINVAL;
return -1;
}
int _alloc_amigafd(BPTR fh, long protection, long flags)
{
struct amigainfo *new = (struct amigainfo *)malloc(sizeof(struct amigainfo));
int fd;
if (!new) { errno = ENOMEM; return -1; }
new->fh = fh;
new->lock = NULL;
new->protection = protection;
new->deleted = FALSE;
new->interactive = IsInteractive(fh);
fd = _alloc_fd(new, flags,
file_select_start, file_select_poll, file_read, file_write,
file_lseek, file_close, file_ioctl);
if (fd < 0) free(new);
return fd;
}
void _init_unixio(BPTR in, int close_in, BPTR out, int close_out,
BPTR error, int close_error)
{
if (_alloc_amigafd(in, -1, FI_READ | (close_in ? 0 : O_NO_CLOSE)) == 0 &&
_alloc_amigafd(out, -1, FI_WRITE | (close_out ? 0 : O_NO_CLOSE)) == 1 &&
_alloc_amigafd(error, -1, FI_WRITE | (close_error ? 0 : O_NO_CLOSE)) == 2)
return;
_fail("Failed to initialise I/O");
}